package spring.aop.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * description:
 * 环绕通知
 * 1. 环绕通知对应整个 try...catch...finally 结构，包括前面四种通知的所有功能。
 * 2. 环绕通知需要在通知中定义目标方法的执行 joinPoint.proceed(args)
 * 3. 需要抛出异常
 */

@Component
@Aspect
public class TxAroundAdvice {

    /**
     * @param joinPoint 目标方法 (获取目标方法信息,多了一个执行方法)
     * @return 目标方法的返回值
     */
    @Around("spring.aop.pointcut.MyPointCut.pc()")
    public Object transaction(ProceedingJoinPoint joinPoint) {

        // 通过ProceedingJoinPoint对象获取外界调用目标方法时传入的实参数组
        Object[] args = joinPoint.getArgs();
        List<Object> argList = Arrays.asList(args);
        System.out.println("args = " + argList);  // args = [1, 0]

        // 声明变量用来存储目标方法的返回值
        Object result = null;

        try {
            // 相当于@Before
            System.out.println("TxAroundAdvice 开启事务");

            // 目标方法执行
            result = joinPoint.proceed(args);
            System.out.println("result = " + result);

            // 相当于@AfterReturning
            System.out.println("TxAroundAdvice 结束事务");

        } catch (Throwable e) {
            // 相当于@AfterThrowing
            System.out.println("Throwable = " + e);
            System.out.println("TxAroundAdvice 事务回滚");
            throw new RuntimeException(e);

        } finally {
            // 相当于@After
            System.out.println("TxAroundAdvice 全部运行结束");
        }

        return result;
    }

}
